#include "bitmap.c"
#include <assert.h>
#include <stdlib.h>
#include <time.h>

void test_shift()
{
	assert(bm_size_to_shift(0) == 5);
	assert(bm_size_to_shift(1) == 5);
	assert(bm_size_to_shift(1023) == 5);
	assert(bm_size_to_shift(1024) == 5);
	assert(bm_size_to_shift(1025) == 10);
	assert(bm_size_to_shift(1026) == 10);
	assert(bm_size_to_shift(1024 * 32) == 10);
	assert(bm_size_to_shift(1024 * 32 + 1) == 15);
	assert(bm_size_to_shift(1024 * 1024) == 15);
	assert(bm_size_to_shift(1024 * 1024 + 1) == 20);
	assert(bm_size_to_shift(1024 * 1024 * 32) == 20);
	assert(bm_size_to_shift(1024 * 1024 * 32 + 1) == 25);
}

void test_setb_getb_with_size(int size)
{
	int i;
	int b[1000];

	struct bitmap* bm = bm_alloc(size);
	assert(bm);

	for (i = 0; i < 1000; ++i) {
		int r = rand() % size;
		assert(bm_getb(bm, r) == 0);
	}

	assert(bm_getb(bm, 0) == 0);
	assert(bm_setb(bm, 0, 1) == 0);
	assert(bm_getb(bm, 0) == 1);
	assert(bm_setb(bm, 0, 0) == 0);
	assert(bm_getb(bm, 0) == 0);

	assert(bm_getb(bm, size - 1) == 0);
	assert(bm_setb(bm, size - 1, 1) == 0);
	assert(bm_getb(bm, size - 1) == 1);
	assert(bm_setb(bm, size - 1, 0) == 0);
	assert(bm_getb(bm, size - 1) == 0);

	assert(bm_setb(bm, size, 1) == -EINVAL);
	assert(bm_getb(bm, size) == 0);

	for (i = 0; i < 1000; ++i) {
		int r = rand() % size;
		b[i] = r;
		assert(bm_setb(bm, r, 1) == 0);
		assert(bm_getb(bm, r) == 1);
	}

	for (i = 0; i < 1000; ++i) {
		assert(bm_setb(bm, b[i], 0) == 0);
	}

	for (i = 1; i < size && i < 1000000; ++i) {
		assert(bm_getb(bm, i) == 0);
	}
	bm_free(bm);
}

void test_setb_getb()
{
	int n = 100;
	test_setb_getb_with_size(1);
	test_setb_getb_with_size(2);
	test_setb_getb_with_size(1023);
	test_setb_getb_with_size(1024);
	test_setb_getb_with_size(1025);
	while (--n > 0) {
		int size = rand() % (1000 * n);
		TRACE("size = %d", size);
		test_setb_getb_with_size(size);
	}
}

void test_nextb_with_size(int size)
{
	int i, s;
	int b[1000];
	unsigned int pos;

	struct bitmap* bm = bm_alloc(size);
	assert(bm);

	s = 0;
	for (i = 0; i < 1000; ++i) {
		int r = 1 + rand() % (size / 1000);
		s += r;
		b[i] = s;
		assert(bm_getb(bm, s) == 0);
		assert(bm_setb(bm, s, 1) == 0);
		assert(bm_getb(bm, s) == 1);
	}

	pos = 0;
	for (i = 0; i < 1000; ++i) {
		assert(bm_getb(bm, b[i]) == 1);
		assert(bm_nextb(bm, &pos) == 1);
		assert(pos == b[i]);
		++pos;
	}
	assert(bm_nextb(bm, &pos) == 0);

	bm_free(bm);
}

void test_nextb()
{
	int n = 100;
	while(--n > 0) {
		int size = rand() % (10000 * n) + 10000;
		TRACE("size = %d", size);
		test_nextb_with_size(size);
	}
}

void test_enc_size()
{
	int i;
	struct bitmap* bm = bm_alloc(1024);
	assert(bm);
	assert(bm_enc_size(bm) == 0);
	bm_setb(bm, 0, 1);
	assert(bm_enc_size(bm) == 2);
	bm_setb(bm, 1, 1);
	assert(bm_enc_size(bm) == 2);
	bm_setb(bm, 30, 1);
	assert(bm_enc_size(bm) == 2);
	bm_setb(bm, 31, 1);
	assert(bm_enc_size(bm) == 2);
	bm_setb(bm, 32, 1);
	assert(bm_enc_size(bm) == 3);

	for (i = 0; i < 1024; ++i)
		assert(bm_setb(bm, i, 1) == 0);
	
	assert(bm_enc_size(bm) == 33);
	bm_free(bm);
}

void test_enc_dec_with_size(int size)
{
	int i;
	unsigned int pos;
	u32* buf;
	size_t s;

	struct bitmap* bm1 = bm_alloc(size);
	struct bitmap* bm2 = bm_alloc(size);
	assert(bm1);
	assert(bm2);

	for (i = 0; i < 1000; ++i) {
		int r = rand() % size;
		assert(bm_setb(bm1, r, 1) == 0);
		assert(bm_getb(bm1, r) == 1);
	}

	s = bm_enc_size(bm1);
	assert(s > 0);
	buf = malloc(sizeof(u32) * s);
	assert(buf);

	assert(s == bm_enc_buf(bm1, buf, s));
	assert(s == bm_dec_buf(bm2, buf, s));

	pos = 0;
	while(bm_nextb(bm1, &pos)) {
		assert(bm_getb(bm2, pos) == 1);
		++pos;
	}

	pos = 0;
	while(bm_nextb(bm2, &pos)) {
		assert(bm_getb(bm1, pos) == 1);
		++pos;
	}

	free(buf);
	bm_free(bm1);
	bm_free(bm2);
}

void test_enc_dec()
{
	int n = 100;
	while(--n > 0) {
		int size = rand();
		TRACE("size = %d", size);
		test_enc_dec_with_size(size);
	}
}

int main()
{
	srand(time(NULL));
	test_enc_dec();
	test_enc_size();
	test_nextb();
	test_setb_getb();
	test_shift();
	return 0;
}
